package org.breathe.dynamic.thread.pool.core.notify;

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.breathe.dynamic.thread.pool.core.notify.alarm.AlarmLimiter;
import org.breathe.dynamic.thread.pool.core.thread.BreatheDtpExecutor;
import org.breathe.thread.pool.common.entity.BreatheDtpProperties;
import org.breathe.thread.pool.common.entity.NotifyItem;
import org.breathe.thread.pool.common.entity.NotifyPlatform;
import org.breathe.thread.pool.common.entity.ThreadPoolExecutorProperties;
import org.breathe.thread.pool.common.enums.NotifyTypeEnum;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 报警的一些通用方法
 * @author: breathe
 * @createTime: 2025-04-10
 */
@Slf4j
public class NotifyHelper {

    protected static final List<String> COMMON_ALARM_KEYS = Lists.newArrayList("alarmType", "threshold");
    protected static final List<String> LIVENESS_ALARM_KEYS =Lists.newArrayList("corePoolSize", "maximumPoolSize", "poolSize", "activeCount");
    protected static final List<String> CAPACITY_ALARM_KEYS = Lists.newArrayList("queueType", "queueCapacity", "queueSize", "queueRemaining");
    protected static final List<String> REJECT_ALARM_KEYS = Lists.newArrayList("rejectType", "rejectCount");
    protected static final Set<String> ALL_ALARM_KEYS =
            Stream.of(COMMON_ALARM_KEYS, CAPACITY_ALARM_KEYS, REJECT_ALARM_KEYS, LIVENESS_ALARM_KEYS)
                    .flatMap(Collection::stream).collect(Collectors.toSet());
    private NotifyHelper() {}

    /**
     * 获取线程池中符合报警类型的报警实体
     * @param executor 线程池
     * @param typeEnum 报警类型
     * @return 一次报警
     */
    public static NotifyItem getNotifyItem(BreatheDtpExecutor executor, NotifyTypeEnum typeEnum) {
        //从线程池中获得所有的报警中心
        List<NotifyItem> notifyItems = executor.getNotifyItems();
        NotifyItem notifyItem = notifyItems.stream()
                //对于每个报警中心，判断报警类型是否相等，并且判断是否报警，我觉得应该把后面的放前面
                .filter(each -> each.isEnabled() && typeEnum.getValue().equalsIgnoreCase(each.getType()))
                .findFirst()
                .orElse(null);
        if (Objects.isNull(notifyItem)) {
            log.warn("breathe dynamic notify, no such [{}] notify item configured, thread pool name: {}", typeEnum.getValue(), executor.getThreadPoolName());
            return null;
        }
        return notifyItem;
    }

    /**
     * 将报警平台注入到报警实体中
     * @param platforms 报警平台
     * @param notifyItems 报警实体
     */
    public static void fillNotifyItems(List<NotifyPlatform> platforms, List<NotifyItem> notifyItems) {
        if (CollUtil.isEmpty(platforms)) {
            log.warn("breathe dynamic thread pool notify, no one notify platforms configuration");
            return ;
        }
        List<String> platformNames = platforms.stream()
                .map(NotifyPlatform::getPlatform)
                .toList();
        notifyItems.forEach(each -> {
            if (CollUtil.isEmpty(each.getPlatforms())) {
                each.setPlatforms(platformNames);
            }
        });
    }

    /**
     * 配置线程池报警实体
     * @param executor 线程池包装
     * @param breatheDtpProperties 项目配置
     * @param threadPoolExecutorProperties 线程池配置
     */
    public static void setExecutorNotifyItems(BreatheDtpExecutor executor, BreatheDtpProperties breatheDtpProperties, ThreadPoolExecutorProperties threadPoolExecutorProperties) {
        fillNotifyItems(breatheDtpProperties.getPlatforms(), threadPoolExecutorProperties.getNotifyItems());
        List<NotifyItem> oldNotifyItems = executor.getNotifyItems();
        Map<String, NotifyItem> oldNotifyItemMap = oldNotifyItems.stream()
                .collect(Collectors.toMap(NotifyItem::getType, each -> each, (val1, val2) -> val1));
        threadPoolExecutorProperties.getNotifyItems().forEach(each -> {
            NotifyItem oldNotifyItem = oldNotifyItemMap.get(each.getType());
            if (Objects.nonNull(oldNotifyItem) && oldNotifyItem.getInterval() == each.getInterval()) {
                return ;
            }
            AlarmLimiter.initAlarmLimiter(executor.getThreadPoolName(), each);
        });
    }
}